<?php

use Phalcon\Config;
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Php as PhpEngine;
use Phalcon\Mvc\Url as UrlResolver;
use Phalcon\Mvc\View\Engine\Volt as VoltEngine;
use Phalcon\Mvc\Model\Metadata\Memory as MetaDataAdapter;
use Phalcon\Flash\Direct as Flash;
use Phalcon\Flash\Session as FlashSession;
use Phalcon\Crypt;
use Phalcon\Http\Response\Cookies;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Logger\Adapter\File as FileLogger;
use Phalcon\Cache\Frontend\Data as FrontData;
use Phalcon\Security;
use Phalcon\Logger\Adapter\Stream as StreamAdapter;
use Phalcon\Logger\Multiple as MultipleStream;
use Phalcon\Logger\Adapter\File as FileAdapter;
use Phalcon\Logger\Formatter\Line as FormatterLine;
use League\Flysystem\Filesystem;
use League\Flysystem\Adapter\Local;
use Phalcon\Mvc\Router;
use Phalcon\Mvc\Model\Manager as ModelManager;
use Phalcon\Mvc\Model\Transaction\Manager as TransactionManager;
use Phalcon\Mvc\Dispatcher;


/**
 * Shared configuration service
 */
$di->setShared('config', function () {
    $config_path =  BASE_PATH . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR;

    $config = new \Phalcon\Config();

    if($handle = opendir($config_path)){
        while($file = readdir($handle)){
            $info = pathinfo($file);
            if(isset($info['extension']) && $info['extension'] === 'php'){
                $data = require ($config_path . DIRECTORY_SEPARATOR . $file);
                if(is_array($data)){
                    $config->merge(new Config([$info['filename'] => $data]));
                }
            }
        }
    }

    return $config;
});

$config = $di->get('config');

/**
 * The URL component is used to generate all kind of urls in the application
 */
$di->setShared('url', function () use($config) {

    $url = new UrlResolver();
    $url->setBaseUri($config->application->baseUri);

    return $url;
});

/**
 * Setting up the view component
 */
$di->setShared('view', function () {
    $config = $this->getConfig();

    $view = new View();
    $view->setDI($this);
    $view->setViewsDir($config->application->viewsDir);

    $view->registerEngines([
        '.volt' => function ($view) {
            $config = $this->getConfig();

            $volt = new VoltEngine($view, $this);

            $volt->setOptions([
                'compiledPath'      => $config->application->cacheDir,
                'compiledSeparator' => '_',
                'compileAlways'     => true
            ]);

            return $volt;
        },
        '.phtml' => PhpEngine::class

    ]);

    return $view;
});

/**
 * Database connection is created based in the parameters defined in the configuration file
 */
$di->setShared('db', function () use($config) {

    $connection = new $config->database->adapter([
        'host'     => $config->database->host,
        'username' => $config->database->username,
        'password' => $config->database->password,
        'dbname'   => $config->database->dbname,
        'charset'  => $config->database->charset
    ]);

    $eventsManager = new EventsManager();
    $connection->setEventsManager($eventsManager);
    $logger = new FileLogger($config->database->logs);
    $eventsManager->attach("dbRead:beforeQuery",function($event,$connection)use($logger){
        $logger->log($connection->getSQLStatement(),\Phalcon\Logger::INFO);
    });

    return $connection;
});

/**
 * If the configuration specify the use of metadata adapter use it or use memory otherwise
 */
$di->setShared('modelsMetadata', function () {
    return new MetaDataAdapter();
});

$di->setShared('modelsManager',function (){
    return new ModelManager();
});

$di->setShared('transactionManager',function (){
    $transactionManager =  new TransactionManager();

    return $transactionManager;
});
/**
 * Register the session flash service with the Twitter Bootstrap classes
 */
$di->setShared('flash', function () {
    return new Flash([
        'error'   => 'alert alert-danger',
        'success' => 'alert alert-success',
        'notice'  => 'alert alert-info',
        'warning' => 'alert alert-warning'
    ]);
});
$di->setShared('flashSession',function (){

    $flash =  new FlashSession([
        'error'   => 'alert alert-danger',
        'success' => 'alert alert-success',
        'notice'  => 'alert alert-info',
        'warning' => 'alert alert-warning'
    ]);

    return $flash;
});

/**
 * Start the session the first time some component request the session service
 */
$di->setShared('session', function () use($config) {

    $session = new $config->session->driver($config->session->config);

    if(isset($config->session->config->files)){
        @mkdir($config->session->config->files,0766,true);
        session_save_path($config->session->config->files);
    }
    if(isset($config->session->config->lifetime)){
        session_cache_expire($config->session->config->lifetime);
    }

    $session->start();

    return $session;

});

$di->setShared('request', 'Phalcon\Http\Request');
$di->setShared('response', 'Phalcon\Http\Response');

$di->setShared('cookies', function () use($config){
    $cookies = new Cookies();

    $cookies->useEncryption($config->cookie->secure);

    return $cookies;
});

// 注册加密组件
$di->setShared('crypt', function () use ($config) {
    $crypt = new Crypt();
    $crypt->setPadding(\Phalcon\Crypt::PADDING_ZERO);
    // 设置全局加密密钥
    $crypt->setKey($config->security->key);
    return $crypt;
});

$di->setShared('cache', function ()use($config){

    $frontCache = new FrontData(
        [
            "lifetime" => 172800,
        ]
    );
    $options = $config->cache->config->toArray();

    if(isset($options['auth']) && empty($options['auth'])){
        unset($options['auth']);
    }
    if(isset($config->cache->config->cacheDir)){
        @mkdir($config->cache->config->cacheDir);
    }

    $cache = new $config->cache->adapter($frontCache,$options);


    return $cache;
});

$di->setShared("security", function () {
    $security = new Security();

    // Set the password hashing factor to 12 rounds
    $security->setWorkFactor(12);

    return $security;
});

//日志适配器
$di->setShared('logger',function (){
    // 发送消息到stderr
    $logger = new MultipleStream();

    $file = new FileAdapter(BASE_PATH . "/runtime/logs/access.log");
    $formatter = new FormatterLine(null,'Y-m-d H:i:s');

    $file->setFormatter($formatter);

    $logger->push($file);
    $logger->push(new StreamAdapter("php://stdout"));
    $logger->push(new StreamAdapter("php://stderr"));

    return $logger;

});

/**
 * 注入 redis 服务器
 */
$di->setShared('redis',function () use($config) {

    if (!isset($config->redis)) {
        throw new \Exception('没有配置 Redis 服务器');
    }
    ini_set('default_socket_timeout', -1);
    $redis = new \Redis();

    if(isset($config->redis->persistent) && $config->redis->persistent) {
        $redis->pconnect($config->redis->host,$config->redis->port);
    }else{
        $redis->connect($config->redis->host,$config->redis->port,300);
    }

    if(isset($config->redis->auth) && empty($config->redis->auth) === false) {
        $redis->auth($config->redis->auth);
    }

    $redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_IGBINARY);
    $redis->setOption(\Redis::OPT_READ_TIMEOUT,-1);

    if(isset($config->redis->index)){
        $redis->select(intval($config->redis->index));
    }
    if(isset($config->redis->prefix)){
        $redis->setOption(\Redis::OPT_PREFIX,$config->redis->prefix);
    }

    return $redis;
});

$di->setShared('storage',function () use($config) {
    $adapter = new Local('/');

    $filesystem = new Filesystem($adapter, ['disable_asserts' => true,'root' => '/']);
    $filesystem->addPlugin(new League\Flysystem\Plugin\GetWithMetadata());

    return $filesystem;
});

$di->setShared('router',function (){

    $router = new Router();

    include BASE_PATH . '/routes/routers.php';

    return $router;
});

$di->setShared('filter',function (){
    $filter = new Phalcon\Filter();

    $filter->add('ipv4',function ($value){
        return  filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
    });
    return $filter;
});

$di->setShared("dispatcher", function () {

    $eventsManager = new EventsManager;
    //  $eventsManager->attach('dispatch:beforeDispatch', new SecurityPlugin());

    $dispatcher = new Dispatcher();

    $dispatcher->setEventsManager($eventsManager);
    $dispatcher->setDefaultNamespace('PhalconFramework\Http\Controllers');

    return $dispatcher;
});


